package com.tian.hello.customerview

import android.content.Context
import android.graphics.*
import android.util.AttributeSet
import android.util.Log
import android.view.View
import java.util.*
import kotlin.math.min

/**
 * Converts six items into an ObservableSource that emits those items.
 * <p>
 * <img width="640" height="186" src="https://raw.github.com/wiki/ReactiveX/RxJava/images/rx-operators/just.6.png" alt="">
 * <dl>
 *  <dt><b>Scheduler:</b></dt>
 * </dl>
 */
class TianWatch @JvmOverloads constructor(
        context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {

    private val hourPointWidth = 15f       // 时针宽度
    private val minutePointWidth = 10f     // 分针宽度
    private val secondPointWidth = 4f      // 秒针宽度
    private val watchLineWidth = 4f        // 表盘的宽度

    private val pointRange = 20f           // 指针弧形宽度
    private val numberSpace = 25f          // 刻度与数字之间的间距

    private val scaleMax = 50f             // 整点刻度尺寸
    private val scaleMin = 25f             // 非整点刻度尺寸

    private var watchWidth = 0f            // 控件的宽度
    private var watchHeight = 0f           // 控件的高度

    private var radius = 300f              // 默认半径

    private val paint by lazy { Paint() }  // 画笔
    private val rect by lazy { Rect() }    // 矩形


    init {
        paint.textSize = 35f
        paint.typeface = Typeface.DEFAULT_BOLD
        paint.isAntiAlias = true
    }

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
        // 整个表盘宽度 = 圆的宽度 + 2倍圆弧宽度
        watchWidth = onMeasureSpec(widthMeasureSpec) + watchLineWidth * 2
        watchHeight = onMeasureSpec(heightMeasureSpec) + watchLineWidth * 2
        // 重新计算半径
        radius = (watchWidth - watchLineWidth * 2) / 2
        setMeasuredDimension(watchWidth.toInt(), watchHeight.toInt())

    }

    private fun onMeasureSpec(measureSpec: Int): Int {
        val specMode = MeasureSpec.getMode(measureSpec)
        val specSize = MeasureSpec.getSize(measureSpec)

        return when (specMode) {
            MeasureSpec.EXACTLY -> specSize
            else -> min((radius * 2).toInt(), specSize)
        }
    }

    override fun onDraw(canvas: Canvas) {
        // 寻找圆心位置
        val centerX = watchWidth / 2
        val centerY = watchHeight / 2

        // 把当前画布的原点位置，移动到圆心，为后续的绘制减少计算
        canvas.translate(centerX, centerY)

        // 绘制表盘
        drawClockCircle(canvas)
        // 绘制刻度
        drawScale(canvas)
        // 绘制指针
        drawPointer(canvas)
        // 间隔一秒绘制
        postInvalidateDelayed(1000)
    }

    /**
     * 绘制 表盘
     */
    private fun drawClockCircle(canvas: Canvas) {
        paint.strokeWidth = watchLineWidth  // 设置画笔宽
        paint.color = Color.BLACK           // 设置画笔颜色
        paint.style = Paint.Style.STROKE    // 设置绘制方式 为空心

        // 绘制圆, 这里圆心位置就是原点，因为在上面已经做了原点移动操作
        canvas.drawCircle(0f, 0f, radius, paint)
    }

    /**
     * 绘制表盘刻度
     */
    private fun drawScale(canvas: Canvas) {
        for (index in 1..60) {
            // 刻度的绘制以12点方向为准，每次将表盘旋转顺时针6度
            canvas.rotate(6f, 0f, 0f)

            // 整点刻度点绘制
            if (index % 5 == 0) {
                paint.strokeWidth = 4.0f
                // 绘制刻度线, 注意 因为这里每次旋转6度，其实刻度度绘制都是在12点方向进行绘制的
                canvas.drawLine(0f, -radius, 0f, -radius + scaleMax, paint)
                // 整点的时候需要绘制文本
                drawText2(index, canvas)
//                drawText1(index,canvas)
            } else {
                paint.strokeWidth = 2.0f
                canvas.drawLine(0f, -radius, 0f, -radius + scaleMin, paint)
            }
        }
    }

    /**
     * 这样绘制的出来的 数字 在6点这些位置是倒过来的
     */
    private fun drawText1(index: Int, canvas: Canvas) {
        // 整点的时候需要绘制文本
        paint.strokeWidth = 1f
        paint.style = Paint.Style.FILL // 实心绘制文本
        // 文本内容
        val numberStr = (index / 5).toString()
        // 初始化，能包裹文本的矩形对象
        paint.getTextBounds(numberStr, 0, numberStr.length, rect)

        // 因为当前在 12点方向，所以 数字要居中 启点x = -rect.width() / 2.0f，启点y = -radius + scaleMax + numberSpace + rect.height() / 2
        canvas.drawText(numberStr, -rect.width() / 2.0f, -radius + scaleMax + numberSpace + rect.height() / 2, paint)
    }

    /**
     *  ### 处理绘制文字 颠倒的问题
     *  - 1、将原点从圆心，移动到(0,-radius + numberSpace + scaleMax + (rect.height() / 2))
     *  - 2、旋转canvas，旋转的角度是 - index * 6，是为了保证 文本是垂直向下的不颠倒
     *  - 3、因为原点被移动到y轴上的 -radius + numberSpace + scaleMax + (rect.height() / 2) 位置，所以绘制时，
     *  x轴 = -rect.width() / 2，y轴=rect.height()
     *  - 4、[canvas save 与restore](https://blog.csdn.net/tiankongcheng6/article/details/83000247)
     */
    private fun drawText2(index: Int, canvas: Canvas) {
        // 保存画布之前的状态
        canvas.save()
        // 设置画笔宽度
        paint.strokeWidth = 1.0F
        // 设置画笔实心风格
        paint.style = Paint.Style.FILL
        // 文本内容
        val numberStr = (index / 5).toString()
        // 初始化，能包裹文本的矩形对象
        paint.getTextBounds(numberStr, 0, numberStr.length, rect)

        canvas.translate(0F, -radius + numberSpace + scaleMax + (rect.height() / 2))
        canvas.rotate((index * -6).toFloat())
        canvas.drawText(numberStr, -rect.width() / 2.toFloat(), rect.height().toFloat() / 2, paint)
        // 恢复画布之前的状态
        canvas.restore()
    }

    /**
     * 绘制 时分秒 指针
     */
    private fun drawPointer(canvas: Canvas) {
        // 获取当前时间
        val calendar = Calendar.getInstance()
        val hour = calendar.get(Calendar.HOUR)
        val minute = calendar.get(Calendar.MINUTE)
        val second = calendar.get(Calendar.SECOND)

        // 计算时分秒针转过的角度
        val hourAngle = (360 / 12) * (hour + minute / 60f)
        val minuteAngle = (360 / 60) * (minute + second / 60f)
        val secondAngle = (360 / 60) * second

        // 开始时针绘制
        canvas.save()
        // 当前原点在 圆心，这个时候圆心坐标是(0,0),将画布顺时针旋转 "时针扫过的角度"，然后开始绘制
        canvas.rotate(hourAngle, 0f, 0f)
        val rectHour = RectF(-hourPointWidth / 2, -radius / 2, hourPointWidth / 2, radius / 6)

        paint.color = Color.BLUE
        paint.style = Paint.Style.STROKE
        paint.strokeWidth = hourPointWidth

        canvas.drawRoundRect(rectHour, pointRange, pointRange, paint)
        canvas.restore()

        // 绘制分针
        canvas.save()
        // 旋转到分针的角度
        canvas.rotate(minuteAngle, 0F, 0F)
        val rectMinute = RectF(
                -minutePointWidth / 2,
                -radius * 3.5f / 5,
                minutePointWidth / 2,
                radius / 6
        )
        // 设置分针画笔属性
        paint.color = Color.BLACK
        paint.strokeWidth = minutePointWidth
        canvas.drawRoundRect(rectMinute, pointRange, pointRange, paint)
        canvas.restore()

        // 绘制秒针
        canvas.save()
        canvas.rotate(secondAngle.toFloat(), 0F, 0F)
        val rectSecond = RectF(
                -secondPointWidth / 2,
                -radius + 10,
                secondPointWidth / 2,
                radius / 6
        )
        // 设置秒针画笔属性
        paint.strokeWidth = secondPointWidth
        paint.color = Color.RED
        canvas.drawRoundRect(rectSecond, pointRange, pointRange, paint)
        canvas.restore()

        // 绘制原点
        paint.style = Paint.Style.FILL
        canvas.drawCircle(0F, 0F, secondPointWidth * 4, paint)
    }

}